﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Kwan.Core;
using System.Data;
using System.Configuration;
namespace Kwan.Data
{
    /// <summary>
    /// 数据处理对象
    /// </summary>
    public class DBContext
    {
        static DBContext()
        {

            Config = (KwanDataSection)ConfigurationManager.GetSection("Kwandata");
            LoadEntity();
           
            
        }
        internal static void Init()
        {
        }
        static void LoadEntity()
        {
            if (Config != null)
            {
                Assembly assembly;
                foreach (AssemblyElement ae in Config.Assemblies)
                {
                    assembly = Assembly.Load(ae.Type);
                    LoadEntityByAssembly(assembly);
                }
            }
            else
            {
                Config = new KwanDataSection(10);
            }
        }
        public static void LoadEntityByAssembly(Assembly assembly)
        {
            foreach (Type type in assembly.GetTypes())
            {
                if (type.IsClass && Functions.GetTypeAttributes<Mappings.TableAttribute>(type, false).Length > 0)
                {
                    Mappings.ObjectMapper.GetOM(type);
                }
            }
        }
        public static void LoadEntity(params Type[] types)
        {
            foreach (Type item in types)
            {
                Mappings.ObjectMapper.GetOM(item);
            }
        }
        public static Kwan.Core.AsyncDelegate<IDbCommand> Executing
        {
            get;
            set;

        }
        internal static KwanDataSection Config
        {
            get;
            set;
        }
        internal static ConnectionHandler CurrentHandler(string db)
        {

            if (db == null)
                throw new KwanDataException(DataMsg.CONNECTION_STRING_ERROR);
            if (HandlerTable.ContainsKey(db))
                return HandlerTable[db];
            return null;
        }
        [ThreadStatic]
        static Dictionary<string, ConnectionHandler> mHandlerTable = new Dictionary<string, ConnectionHandler>(200);

        internal static Dictionary<string, ConnectionHandler> HandlerTable
        {
            get
            {
                if (mHandlerTable == null)
                    mHandlerTable = new Dictionary<string, ConnectionHandler>(10);
                return mHandlerTable;

            }
        }
        internal static void AddConnectionHandler(string db, IDriver driver)
        {


            IDbConnection conn = driver.Connection;
            conn.ConnectionString = db;
            conn.Open();
            ConnectionHandler ch = new ConnectionHandler(conn);
            ch.Driver = driver;
            HandlerTable.Add(db, ch);

        }
        internal static void RemoveConnetionHandler(string db)
        {

            if (HandlerTable.ContainsKey(db))
                HandlerTable.Remove(db);

        }
        public static void SetConnectionString(ConnectionType connection, string connectionString)
        {
            if (connection.GetHashCode() >= Config.Connections.Count)
                throw new KwanDataException(string.Format(DataMsg.DATABASE_SETTING_NOTFOUND, connection));
            Config.Connections[connection.GetHashCode()].SetConnection(connectionString);

        }
        public static string GetConnectionString(ConnectionType connection)
        {
            if (connection.GetHashCode() >= Config.Connections.Count)
                throw new KwanDataException(string.Format(DataMsg.DATABASE_SETTING_NOTFOUND, connection));
            return Config.Connections[connection.GetHashCode()].ConnectionString;
        }
        public static void SetConnectionDriver<T>(ConnectionType connection) where T : IDriver
        {
            if (connection.GetHashCode() >= Config.Connections.Count)
                throw new KwanDataException(string.Format(DataMsg.DATABASE_SETTING_NOTFOUND, connection));
            Config.Connections[connection.GetHashCode()].SetDriver<T>();
        }
        
        public static IConnectinContext GetConnection(ConnectionType connection)
        {
            if (connection.GetHashCode() > Config.Connections.Count)
                throw new KwanDataException(string.Format(DataMsg.DATABASE_SETTING_NOTFOUND, connection));
            ConnectionElement ce = Config.Connections[connection.GetHashCode()];
            IDriver driver = ce.Driver;
            if (driver == null)
                throw new KwanDataException(string.Format(DataMsg.DATABASE_SETTING_NOTFOUND, ce.Name));
            return new ConnectionContext(ce.ConnectionString, driver, connection);
        }
        public static IConnectinContext Context10
        {
            get
            {
                return GetConnection(ConnectionType.Context10);
            }
        }
        public static IConnectinContext Context1
        {
            get
            {
                return GetConnection(ConnectionType.Context1);
            }
        }
        public static IConnectinContext Context2
        {
            get
            {
                return GetConnection(ConnectionType.Context2);
            }
        }
        public static IConnectinContext Context3
        {
            get
            {
                return GetConnection(ConnectionType.Context3);
            }
        }
        public static IConnectinContext Context4
        {
            get
            {
                return GetConnection(ConnectionType.Context4);
            }
        }
        public static IConnectinContext Context5
        {
            get
            {
                return GetConnection(ConnectionType.Context5);
            }
        }
        public static IConnectinContext Context6
        {
            get
            {
                return GetConnection(ConnectionType.Context6);
            }
        }
        public static IConnectinContext Context7
        {
            get
            {
                return GetConnection(ConnectionType.Context7);
            }
        }
        public static IConnectinContext Context8
        {
            get
            {
                return GetConnection(ConnectionType.Context8);
            }
        }
        public static IConnectinContext Context9
        {
            get
            {
                return GetConnection(ConnectionType.Context9);
            }
        }

        public static T Load<T>(object id) where T : IEntityState, new()
        {
            using (IConnectinContext cc = Context1)
            {
                return Load<T>(id, cc);
            }
        }
        public static int Add(params Mappings.DataObject[] obj)
        {
            int result = 0;
            using (IConnectinContext cc = DBContext.Context1)
            {
                cc.BeginTransaction();
                result=Add(cc, obj);
                cc.Commit();
            }
            return result;
        }
        public static int Add(IConnectinContext cc, params Mappings.DataObject[] obj)
        {
            int result = 0;
            foreach (Mappings.DataObject item in obj)
            {
                item.EntityState._Loaded = false;
                result=result+ item.Save(cc);
            }
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>Save Count</returns>
        public static int Save(params Mappings.DataObject[] obj)
        {
            int result = 0;
            using (IConnectinContext cc = DBContext.Context1)
            {
                cc.BeginTransaction();
                result=Save(cc, obj);
                cc.Commit();
            }
            return result;
        }
        public static int Save(IConnectinContext cc, params Mappings.DataObject[] obj)
        {
            int result = 0;
            foreach (Mappings.DataObject item in obj)
            {
                result = result+item.Save(cc);
            }
            return result;
        }
        public static int Delete(params Mappings.DataObject[] obj)
        {
            int result = 0;
            using (IConnectinContext cc = DBContext.Context1)
            {
                cc.BeginTransaction();
                result = result+Delete(cc, obj);
                cc.Commit();
            }
            return result;
        }
        public static int Delete(IConnectinContext cc, params Mappings.DataObject[] obj)
        {
            int result = 0;
            foreach (Mappings.DataObject item in obj)
            {
                result = result+item.Delete(cc);
            }
            return result;
        }
        public static IDisposable ChangeTable<T>(string tn) where T : IEntityState, new()
        {
            Mappings.ChangeTables change = new Mappings.ChangeTables();
            change.Add<T>(tn);
            return change;
        }
        public static IDisposable ChangeTable<T,T1>(string tn1,string tn2) 
            where T:IEntityState,new()
            where T1 : IEntityState, new()
        {
            Mappings.ChangeTables change = new Mappings.ChangeTables();
            change.Add<T>(tn1);
            change.Add<T1>(tn2);
            return change;
        }
        public static IDisposable ChangeTable<T, T1,T2>(string tn1, string tn2,string tn3)
            where T : IEntityState, new()
            where T1 : IEntityState, new()
            where T2 : IEntityState, new()
        {
            Mappings.ChangeTables change = new Mappings.ChangeTables();
            change.Add<T>(tn1);
            change.Add<T1>(tn2);
            change.Add<T2>(tn3);
            return change;
        }

        public static IDisposable ChangeTable<T, T1, T2,T3>(string tn1, string tn2, string tn3,string tn4)
            where T : IEntityState, new()
            where T1 : IEntityState, new()
            where T2 : IEntityState, new()
            where T3 : IEntityState, new()
        {
            Mappings.ChangeTables change = new Mappings.ChangeTables();
            change.Add<T>(tn1);
            change.Add<T1>(tn2);
            change.Add<T2>(tn3);
            change.Add<T3>(tn4);
            return change;
        }

        public static IDisposable ChangeTable<T, T1, T2, T3,T4>(string tn1, string tn2, string tn3, string tn4,string tn5)
            where T : IEntityState, new()
            where T1 : IEntityState, new()
            where T2 : IEntityState, new()
            where T3 : IEntityState, new()
            where T4 : IEntityState, new()
        {
            Mappings.ChangeTables change = new Mappings.ChangeTables();
            change.Add<T>(tn1);
            change.Add<T1>(tn2);
            change.Add<T2>(tn3);
            change.Add<T3>(tn4);
            change.Add<T4>(tn5);
            return change;
        }

        public static T Load<T>(object id, IConnectinContext cc) where T : IEntityState, new()
        {
            Mappings.ObjectMapper om = Mappings.ObjectMapper.GetOM(typeof(T));
            if (om.ID == null)
                throw new KwanDataException(DataMsg.ID_MAP_NOTFOUND);
            Expression exp = new Expression();
            exp.SqlText.Append(om.ID.ColumnName + "=@p1");
            exp.Parameters.Add(new Command.Parameter { Name = "p1", Value = id });
            return EntityBase.ExOnListFirst<T>(cc, om.GetSelect(), exp, null, null);

        }
        public static void TransactionExecute(ConnectionType conn, Action<IConnectinContext> handler)
        {
            using (IConnectinContext cc = DBContext.GetConnection(conn))
            {
                cc.BeginTransaction();
                handler(cc);
                cc.Commit();
            }
        }
        public static void TransactionExecute(Action<IConnectinContext> handler)
        {
            using (IConnectinContext cc = DBContext.Context1)
            {
                cc.BeginTransaction();
                handler(cc);
                cc.Commit();
            }
        }
        public static void TransactionExecute(IConnectinContext cc, Action<IConnectinContext> handler)
        {
            using (cc)
            {
                cc.BeginTransaction();
                handler(cc);
                cc.Commit();
            }
        }

        public static int SaveAsClone(IConnectinContext cc, Mappings.DataObject data)
        {
            Type type = data.GetType();
            Mappings.ObjectMapper om = Mappings.ObjectMapper.GetOM(type);
            Mappings.DataObject result = (Mappings.DataObject)Activator.CreateInstance(type);
            OnClone(data, result, om);
            return Save(cc, result);
        }
        public static int SaveAsClone(Mappings.DataObject data)
        {
           using(IConnectinContext cc = DBContext.Context1)
           {
               return SaveAsClone(cc, data);
           }

        }
        private static void OnClone(object source, object newobj, Mappings.ObjectMapper om)
        {
            object value;
            Mappings.PropertyMapper pm = om.ID;
            if (pm != null)
            {
                value = pm.Handler.Get(source);
                if (value != null)
                    pm.Handler.Set(newobj, value);
            }
            foreach (Mappings.PropertyMapper p in om.Properties)
            {
                value = p.Handler.Get(source);
                if (value != null)
                    p.Handler.Set(newobj, value);
            }
        }
        public static T Clone<T>(T source) where T : IEntityState, new()
        {
            T item = new T();
          
            Mappings.ObjectMapper om = Mappings.ObjectMapper.GetOM(typeof(T));
            OnClone(source, item, om);
            return item;

        }

    }
   
   
}
